package com.imut.lagain.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.imut.lagain.entity.Notification;
import com.imut.lagain.entity.NotificationTemplate;
import com.imut.lagain.repository.NotificationTemplateRepository;
import com.imut.lagain.service.NotificationTemplateService;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
public class NotificationTemplateServiceImpl implements NotificationTemplateService {
    private static final Logger log = LoggerFactory.getLogger(NotificationTemplateServiceImpl.class);

    @Resource
    private NotificationTemplateRepository templateRepository;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    private static final String TEMPLATE_CACHE_KEY = "notification:template:";
    private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\{\\{([^}]+)\\}\\}");

    @Override
    @Transactional
    public NotificationTemplate createTemplate(NotificationTemplate template) {
        try {
            validateTemplate(template);

            QueryWrapper<NotificationTemplate> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("code", template.getCode());
            if (templateRepository.selectCount(queryWrapper) > 0) {
                throw new RuntimeException("Template code already exists: " + template.getCode());
            }

            template.setCreatedAt(LocalDateTime.now());
            template.setUpdatedAt(LocalDateTime.now());
            template.setIsDeleted(false);

            templateRepository.insert(template);
            NotificationTemplate saved = templateRepository.selectById(template.getId());
            log.info("Template created successfully: {}", saved.getCode());
            return saved;
        } catch (Exception e) {
            log.error("Failed to create template", e);
            throw new RuntimeException("Failed to create template: " + e.getMessage());
        }
    }

    @Override
    @Transactional
    public NotificationTemplate updateTemplate(Long templateId, NotificationTemplate template) {
        try {
            NotificationTemplate existing = templateRepository.selectById(templateId);
            if (existing == null) {
                throw new RuntimeException("Template not found: " + templateId);
            }

            QueryWrapper<NotificationTemplate> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("code", template.getCode()).ne("id", templateId);
            if (templateRepository.selectCount(queryWrapper) > 0) {
                throw new RuntimeException("Template code already exists: " + template.getCode());
            }

            validateTemplate(template);

            existing.setName(template.getName());
            existing.setCode(template.getCode());
            existing.setType(template.getType());
            existing.setTitle(template.getTitle());
            existing.setContent(template.getContent());
            existing.setUrl(template.getUrl());
            existing.setEnabled(template.getEnabled());
            existing.setPriority(template.getPriority());
            existing.setSendCondition(template.getSendCondition());
            existing.setWechatTemplateId(template.getWechatTemplateId());
            existing.setWechatData(template.getWechatData());
            existing.setUpdatedAt(LocalDateTime.now());

            templateRepository.updateById(existing);

            clearTemplateCache(existing.getCode());
            log.info("Template updated successfully: {}", existing.getCode());
            return existing;
        } catch (Exception e) {
            log.error("Failed to update template", e);
            throw new RuntimeException("Failed to update template: " + e.getMessage());
        }
    }

    @Override
    @Transactional
    public boolean deleteTemplate(Long templateId) {
        try {
            NotificationTemplate template = templateRepository.selectById(templateId);
            if (template == null) {
                return false;
            }

            template.setIsDeleted(true);
            template.setUpdatedAt(LocalDateTime.now());
            templateRepository.updateById(template);

            clearTemplateCache(template.getCode());
            log.info("Template deleted successfully: {}", template.getCode());
            return true;
        } catch (Exception e) {
            log.error("Failed to delete template", e);
            return false;
        }
    }

    @Override
    public Optional<NotificationTemplate> getTemplateById(Long templateId) {
        try {
            NotificationTemplate template = templateRepository.selectById(templateId);
            return Optional.ofNullable(template);
        } catch (Exception e) {
            log.error("Failed to get template", e);
            return Optional.empty();
        }
    }

    @Override
    public Optional<NotificationTemplate> getTemplateByCode(String code) {
        try {
            String cacheKey = TEMPLATE_CACHE_KEY + code;
            NotificationTemplate cached = (NotificationTemplate) redisTemplate.opsForValue().get(cacheKey);
            if (cached != null) {
                return Optional.of(cached);
            }

            QueryWrapper<NotificationTemplate> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("code", code).eq("is_deleted", false);
            NotificationTemplate template = templateRepository.selectOne(queryWrapper);

            if (template != null) {
                redisTemplate.opsForValue().set(cacheKey, template, 30, TimeUnit.MINUTES);
            }

            return Optional.ofNullable(template);
        } catch (Exception e) {
            log.error("Failed to get template by code", e);
            return Optional.empty();
        }
    }

    @Override
    public List<NotificationTemplate> getEnabledTemplates() {
        try {
            return templateRepository.findByEnabledAndIsDeleted(true, false);
        } catch (Exception e) {
            log.error("Failed to get enabled templates", e);
            return new ArrayList<>();
        }
    }

    @Override
    public Optional<NotificationTemplate> getTemplateByWechatTemplateId(String wechatTemplateId) {
        try {
            // 使用QueryWrapper替代findByWechatTemplateIdAndIsDeletedFalse
            QueryWrapper<NotificationTemplate> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("wechat_template_id", wechatTemplateId).eq("is_deleted", false);
            NotificationTemplate template = templateRepository.selectOne(queryWrapper);
            return Optional.ofNullable(template);
        } catch (Exception e) {
            log.error("Failed to query template", e);
            return Optional.empty();
        }
    }

    @Override
    public List<NotificationTemplate> getTemplatesByType(Notification.NotificationType type) {
        try {
            // 使用QueryWrapper替代findByTypeAndIsDeletedFalse
            QueryWrapper<NotificationTemplate> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("type", type.name()).eq("is_deleted", false);
            return templateRepository.selectList(queryWrapper);
        } catch (Exception e) {
            log.error("Failed to query templates", e);
            return Collections.emptyList();
        }
    }

    @Override
    public List<NotificationTemplate> getTemplatesByCreator(Long creatorId) {
        try {
            return templateRepository.findByCreatorIdAndIsDeletedFalse(creatorId);
        } catch (Exception e) {
            log.error("Failed to query templates", e);
            return Collections.emptyList();
        }
    }

    @Override
    public List<NotificationTemplate> getAllEnabledTemplates() {
        try {
            return templateRepository.findAllEnabledTemplates();
        } catch (Exception e) {
            log.error("Failed to query enabled templates", e);
            return Collections.emptyList();
        }
    }

    @Override
    @Transactional
    public boolean enableTemplate(Long templateId) {
        try {
            // 使用update替代updateEnabledStatus
            NotificationTemplate template = new NotificationTemplate();
            template.setId(templateId);
            template.setEnabled(true);
            template.setUpdatedAt(LocalDateTime.now());
            
            int updated = templateRepository.updateById(template);
            
            if (updated > 0) {
                NotificationTemplate updatedTemplate = templateRepository.selectById(templateId);
                if (updatedTemplate != null) {
                    clearTemplateCache(updatedTemplate.getCode());
                }
            }
            
            return updated > 0;
        } catch (Exception e) {
            log.error("Failed to enable template", e);
            return false;
        }
    }

    @Override
    @Transactional
    public boolean disableTemplate(Long templateId) {
        try {
            // 使用update替代updateEnabledStatus
            NotificationTemplate template = new NotificationTemplate();
            template.setId(templateId);
            template.setEnabled(false);
            template.setUpdatedAt(LocalDateTime.now());
            
            int updated = templateRepository.updateById(template);
            
            if (updated > 0) {
                NotificationTemplate updatedTemplate = templateRepository.selectById(templateId);
                if (updatedTemplate != null) {
                    clearTemplateCache(updatedTemplate.getCode());
                }
            }
            
            return updated > 0;
        } catch (Exception e) {
            log.error("Failed to disable template", e);
            return false;
        }
    }

    @Override
    public String renderTemplate(String template, Map<String, Object> data) {
        return renderContent(template, data);
    }

    @Override
    public String renderContent(String templateContent, Map<String, Object> data) {
        if (templateContent == null || data == null) {
            return templateContent;
        }
        
        String result = templateContent;
        Matcher matcher = VARIABLE_PATTERN.matcher(templateContent);
        
        while (matcher.find()) {
            String variable = matcher.group(1);
            Object value = data.get(variable);
            if (value != null) {
                result = result.replace("{{" + variable + "}}", value.toString());
            }
        }
        
        return result;
    }

    @Override
    public Map<String, Object> buildWechatData(NotificationTemplate template, Map<String, Object> data) {
        Map<String, Object> wechatData = new HashMap<>();
        
        // 修复类型转换问题，先检查wechatData的实际类型
        Object wechatDataObj = template.getWechatData();
        if (wechatDataObj != null) {
            try {
                // 根据实际类型处理
                if (wechatDataObj instanceof String) {
                    // 如果是字符串，可能需要特殊处理或跳过
                    log.debug("WechatData is string: {}", wechatDataObj);
                } else if (wechatDataObj instanceof Map) {
                    @SuppressWarnings("unchecked")
                    Map<String, Object> templateData = (Map<String, Object>) wechatDataObj;
                    
                    for (Map.Entry<String, Object> entry : templateData.entrySet()) {
                        String key = entry.getKey();
                        Object value = entry.getValue();
                        
                        if (value instanceof String) {
                            String renderedValue = renderContent((String) value, data);
                            wechatData.put(key, Map.of("value", renderedValue));
                        } else {
                            wechatData.put(key, value);
                        }
                    }
                } else {
                    log.warn("Unexpected wechatData type: {}", wechatDataObj.getClass().getName());
                }
            } catch (Exception e) {
                log.error("Failed to build wechat data", e);
            }
        }
        
        return wechatData;
    }

    @Override
    public boolean validateTemplateData(NotificationTemplate template) {
        if (template == null) {
            return false;
        }
        
        try {
            validateTemplate(template);
            return true;
        } catch (Exception e) {
            log.error("Failed to validate template data", e);
            return false;
        }
    }

    @Override
    public boolean existsByCode(String code) {
        try {
            return templateRepository.existsByCode(code);
        } catch (Exception e) {
            log.error("Failed to check code existence", e);
            return false;
        }
    }

    @Override
    public boolean existsByWechatTemplateId(String wechatTemplateId) {
        try {
            return templateRepository.existsByWechatTemplateId(wechatTemplateId);
        } catch (Exception e) {
            log.error("Failed to check wechat template id existence", e);
            return false;
        }
    }

    @Override
    public boolean checkSendCondition(NotificationTemplate template, Map<String, Object> data) {
        if (template.getSendCondition() == null || template.getSendCondition().isEmpty()) {
            return true;
        }
        
        try {
            return true;
        } catch (Exception e) {
            log.error("Failed to check send condition", e);
            return false;
        }
    }

    @Override
    public boolean checkFrequencyLimit(NotificationTemplate template, Long userId, int currentCount) {
        return true;
    }

    @Override
    public Set<String> extractVariables(String content) {
        Set<String> variables = new HashSet<>();
        if (content != null) {
            Matcher matcher = VARIABLE_PATTERN.matcher(content);
            while (matcher.find()) {
                variables.add(matcher.group(1));
            }
        }
        return variables;
    }

    @Override
    public Map<String, Object> previewTemplate(NotificationTemplate template, Map<String, Object> sampleData) {
        Map<String, Object> preview = new HashMap<>();
        
        try {
            preview.put("title", renderContent(template.getTitle(), sampleData));
            preview.put("content", renderContent(template.getContent(), sampleData));
            preview.put("url", renderContent(template.getUrl(), sampleData));
            
            // 修复枚举引用问题
            if (template.getType() != null && "WECHAT".equals(template.getType().name())) {
                preview.put("wechatData", buildWechatData(template, sampleData));
            }
            
            Set<String> titleVars = extractVariables(template.getTitle());
            Set<String> contentVars = extractVariables(template.getContent());
            Set<String> urlVars = extractVariables(template.getUrl());
            
            Set<String> allVars = new HashSet<>();
            allVars.addAll(titleVars);
            allVars.addAll(contentVars);
            allVars.addAll(urlVars);
            
            preview.put("variables", allVars);
            preview.put("missingVariables", getMissingVariables(allVars, sampleData));
            
        } catch (Exception e) {
            log.error("Failed to preview template", e);
            preview.put("error", e.getMessage());
        }
        
        return preview;
    }

    @Override
    @Transactional
    public NotificationTemplate copyTemplate(Long templateId, String newCode, String newName) {
        try {
            // 使用selectById替代findById
            NotificationTemplate original = templateRepository.selectById(templateId);
            if (original == null) {
                throw new RuntimeException("Original template not found: " + templateId);
            }
            
            // 使用QueryWrapper检查code是否存在
            QueryWrapper<NotificationTemplate> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("code", newCode);
            if (templateRepository.selectCount(queryWrapper) > 0) {
                throw new RuntimeException("New template code already exists: " + newCode);
            }
            
            NotificationTemplate copy = new NotificationTemplate();
            
            copy.setName(newName);
            copy.setCode(newCode);
            copy.setType(original.getType());
            copy.setTitle(original.getTitle());
            copy.setContent(original.getContent());
            copy.setUrl(original.getUrl());
            copy.setEnabled(false);
            copy.setPriority(original.getPriority());
            copy.setSendCondition(original.getSendCondition());
            copy.setWechatTemplateId(null);
            copy.setWechatData(original.getWechatData());
            copy.setCreatedAt(LocalDateTime.now());
            copy.setUpdatedAt(LocalDateTime.now());
            copy.setIsDeleted(false);
            
            // 使用insert替代save
            templateRepository.insert(copy);
            NotificationTemplate saved = templateRepository.selectById(copy.getId());
            log.info("Template copied successfully: {} -> {}", original.getCode(), saved.getCode());
            return saved;
        } catch (Exception e) {
            log.error("Failed to copy template", e);
            throw new RuntimeException("Failed to copy template: " + e.getMessage());
        }
    }

    @Override
    public List<NotificationTemplate> importTemplates(List<NotificationTemplate> templates) {
        List<NotificationTemplate> imported = new ArrayList<>();
        
        for (NotificationTemplate template : templates) {
            try {
                // 使用QueryWrapper检查code是否存在
                QueryWrapper<NotificationTemplate> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("code", template.getCode());
                if (templateRepository.selectCount(queryWrapper) > 0) {
                    log.warn("Template code already exists, skipping import: {}", template.getCode());
                    continue;
                }
                
                template.setCreatedAt(LocalDateTime.now());
                template.setUpdatedAt(LocalDateTime.now());
                template.setIsDeleted(false);
                
                // 使用insert替代save
                templateRepository.insert(template);
                imported.add(template);
                log.info("Template imported successfully: {}", template.getCode());
            } catch (Exception e) {
                log.error("Failed to import template: {}", template.getCode(), e);
            }
        }
        
        return imported;
    }

    @Override
    public List<NotificationTemplate> exportTemplates(List<Long> templateIds) {
        List<NotificationTemplate> exported = new ArrayList<>();
        
        for (Long templateId : templateIds) {
            try {
                // 使用selectById替代findById
                NotificationTemplate template = templateRepository.selectById(templateId);
                if (template != null) {
                    exported.add(template);
                } else {
                    log.warn("Template not found, skipping export: {}", templateId);
                }
            } catch (Exception e) {
                log.error("Failed to export template: {}", templateId, e);
            }
        }
        
        return exported;
    }

    private void validateTemplate(NotificationTemplate template) {
        if (template == null) {
            throw new IllegalArgumentException("Template cannot be null");
        }
        
        if (template.getName() == null || template.getName().trim().isEmpty()) {
            throw new IllegalArgumentException("Template name cannot be empty");
        }
        
        if (template.getCode() == null || template.getCode().trim().isEmpty()) {
            throw new IllegalArgumentException("Template code cannot be empty");
        }
        
        if (template.getType() == null) {
            throw new IllegalArgumentException("Template type cannot be null");
        }
        
        if (template.getTitle() == null || template.getTitle().trim().isEmpty()) {
            throw new IllegalArgumentException("Template title cannot be empty");
        }
        
        if (template.getContent() == null || template.getContent().trim().isEmpty()) {
            throw new IllegalArgumentException("Template content cannot be empty");
        }
        
        // 修复枚举引用问题
        if ("WECHAT".equals(template.getType().name())) {
            if (template.getWechatTemplateId() == null || template.getWechatTemplateId().trim().isEmpty()) {
                throw new IllegalArgumentException("Wechat template ID cannot be empty");
            }
        }
        
        Set<String> titleVars = extractVariables(template.getTitle());
        Set<String> contentVars = extractVariables(template.getContent());
        
        for (String var : titleVars) {
            if (var.trim().isEmpty()) {
                throw new IllegalArgumentException("Invalid variable in title");
            }
        }
        
        for (String var : contentVars) {
            if (var.trim().isEmpty()) {
                throw new IllegalArgumentException("Invalid variable in content");
            }
        }
    }

    private void clearTemplateCache(String code) {
        try {
            String cacheKey = TEMPLATE_CACHE_KEY + code;
            redisTemplate.delete(cacheKey);
            log.debug("Template cache cleared: {}", code);
        } catch (Exception e) {
            log.error("Failed to clear template cache: {}", code, e);
        }
    }

    private Set<String> getMissingVariables(Set<String> requiredVars, Map<String, Object> data) {
        Set<String> missing = new HashSet<>();
        for (String var : requiredVars) {
            if (!data.containsKey(var) || data.get(var) == null) {
                missing.add(var);
            }
        }
        return missing;
    }
}